package wallet

import (
	"context"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"time"

	"gitee.com/magic-mountain/utils/concurrent"
	"gitee.com/magic-mountain/utils/rpc"
	"github.com/filecoin-project/go-address"
	"github.com/filecoin-project/go-state-types/crypto"
	"github.com/syndtr/goleveldb/leveldb"

	"github.com/urfave/cli"
)

func getwallet(cctx *cli.Context) (Iwallet, func(), error) {
	if cctx.Args().First() == "remote" {
		var w IwalletStruct = IwalletStruct{}
		closer, err := rpc.GetRpcClient(cctx.GlobalString("token"), cctx.GlobalString("url"), "wallet", &w.Internal)
		return &w, closer, err
	} else if cctx.Args().First() == "remotes" {
		var w IwalletService = IwalletService{Clist: concurrent.New()}
		urls := cctx.GlobalStringSlice("urls")

		for _, url := range urls {
			var ws IwalletStruct = IwalletStruct{}
			c, err := rpc.GetRpcClient(cctx.GlobalString("token"), url, "wallet", &ws.Internal)
			if err != nil {
				fmt.Println(err)
			}
			// if _,ok:= {

			// }

			w.Clist.PushFront(&rpc.RpcService{V: &ws, Url: url, Closer: c})
			// addr := w.list[url].(Iwallet).Default(context.Background())
			// fmt.Println(addr)
		}
		return &w, nil, nil
	} else {
		d, err := leveldb.OpenFile(filepath.Dir(os.Args[0]), nil)
		closer := func() {
			defer d.Close()
		}

		if err != nil {
			closer()
			return nil, nil, err
		}
		w, err := Newwallet(cctx.GlobalString("password"), d)
		return w, closer, err
	}

}

func ApendWalletCmd(app *cli.App) {
	gflgs := []cli.Flag{
		cli.StringFlag{
			Name:     "password,p",
			Value:    "123456",
			Usage:    "钱包密码",
			Required: false,
		}, cli.StringFlag{
			Name:     "url,u", // 配置名称
			Value:    ":10106",
			Required: false,
			Usage:    "默认地址", // 配置描述
		},
		cli.StringSliceFlag{
			Name:     "urls,us",
			Value:    &cli.StringSlice{"fe80::215:5dff:fe32:e7bd:10106", "127.0.0.1:10106", "192.168.145.75:10106", "0.0.0.0:10106", "0.0.0.0:10106"},
			Required: false,
			Usage:    "默认地址列表",
		},
		cli.StringFlag{
			Name:        "token,t", // 配置名称
			Value:       "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJBbGxvdyI6WyJyZWFkIiwid3JpdGUiLCJzaWduIiwiYWRtaW4iXX0.ae22SYWjZ_RJRRhfWDpVFzWThu_6EQ-iBgAn8vdrR-w",
			Required:    false,
			Usage:       "jwt token", // 配置描述
			Destination: &rpc.Cfg.Token,
		},
	}
	app.Flags = append(app.Flags, gflgs...)
	wcmd := []cli.Command{*InitCmd, *NewCmd, *DefaultCmd, *DeleteCmd, *SetdefaultCmd, *ListCmd, *ExportCmd, *ImportCmd, *SignCmd, *VerifyCmd, *RpcCmd}
	app.Commands = append(app.Commands, wcmd...)
}

var InitCmd = &cli.Command{
	Name:  "init",
	Usage: "初始化钱包",

	Flags: []cli.Flag{
		cli.IntFlag{
			Name:  "type,t", // 配置名称
			Value: 1,        // 缺省配置值
			Usage: "SigType	SigTypeSecp256k1=1 SigTypeBLS=2", // 配置描述
		},
	},
	Action: func(cctx *cli.Context) error {

		// d, err := leveldb.NewDatastore(filepath.Dir(os.Args[0]), nil)
		// defer d.Close()
		// if err != nil {
		// 	return err
		// }
		// w, err := Newwallet(cctx.GlobalString("password"), d)
		w, c, err := getwallet(cctx)
		defer c()
		if err != nil {
			return err
		}

		addr, err := w.Init(context.Background(), crypto.SigType(cctx.Int("type")))
		if err != nil {
			return err
		}
		fmt.Printf("创建了一个默认地址:%s\n", addr.String())

		return nil
	},
}

var NewCmd = &cli.Command{
	Name:  "new",
	Usage: "创建一个新的地址",

	Flags: []cli.Flag{
		cli.IntFlag{
			Name:  "type,t", // 配置名称
			Value: 1,        // 缺省配置值
			Usage: "SigType	SigTypeSecp256k1=1 SigTypeBLS=2", // 配置描述
		},
	},
	Action: func(cctx *cli.Context) error {

		w, c, err := getwallet(cctx)
		defer c()
		if err != nil {
			return err
		}

		addr, err := w.New(context.Background(), crypto.SigType(cctx.Int("type")))
		if err != nil {
			return err
		}
		fmt.Println(addr.String())

		return nil
	},
}

type addrbase32 struct {
	GAddrs [1][]byte
}

var ListCmd = &cli.Command{
	Name:  "list",
	Usage: "显示所有地址",

	Flags: []cli.Flag{},
	Action: func(cctx *cli.Context) error {
		w, _, err := getwallet(cctx)
		if err != nil {
			return err
		}
		//defer c()

		ctxout, cancel := context.WithTimeout(context.Background(), time.Second*500)
		defer cancel()
		addrs, err := w.List(ctxout)
		if err != nil {
			fmt.Println(err)
		}

		for _, value := range addrs {
			fmt.Println(value.String())

			//addrss := addrbase32{[1][]byte{value.Payload()}}
			jsonbytes, _ := json.Marshal(value.Payload())
			fmt.Printf("%s\n", jsonbytes)
		}
		// for i := 0; i < 10; i++ {
		// 	time.Sleep(time.Second * 10)
		// 	addrs, err = w.List(ctxout)
		// 	if err != nil {
		// 		fmt.Println(err)
		// 	}

		// 	for _, value := range addrs {
		// 		fmt.Println(value.String())
		// 	}

		// }

		return nil
	},
}

var DeleteCmd = &cli.Command{
	Name:  "delete",
	Usage: "创建一个新的地址",

	Flags: []cli.Flag{
		cli.StringFlag{
			Name:     "addr,a",
			Required: true,
			Usage:    "地址",
		},
	},
	Action: func(cctx *cli.Context) error {
		w, c, err := getwallet(cctx)
		defer c()
		if err != nil {
			return err
		}

		addr, err := address.NewFromString(cctx.String("addr"))
		if err != nil {
			return err
		}
		err = w.Delete(context.Background(), addr)
		if err != nil {
			return err
		} else {
			fmt.Println("删除成功")
		}

		return nil
	},
}

var SignCmd = &cli.Command{
	Name:  "sign",
	Usage: "数据签名",

	Flags: []cli.Flag{

		cli.StringFlag{
			Name:     "msg,m",
			Required: true,
			Usage:    "要签名的数据",
		},
	},
	Action: func(cctx *cli.Context) error {
		w, c, err := getwallet(cctx)
		defer c()
		if err != nil {
			return err
		}

		sig, err := w.SignDefault(context.Background(), []byte(cctx.String("msg")))
		if err != nil {
			return err
		}
		sigBytes := append([]byte{byte(sig.Type)}, sig.Data...)
		fmt.Println(hex.EncodeToString(sigBytes))
		return nil
	},
}

var VerifyCmd = &cli.Command{
	Name:  "verify",
	Usage: "验证数据签名",

	Flags: []cli.Flag{
		cli.StringFlag{
			Name:     "sign,s",
			Required: true,
			Usage:    "已签名的数据",
		},
		cli.StringFlag{
			Name:     "msg,m",
			Required: true,
			Usage:    "原始数据",
		},
		cli.StringFlag{
			Name:     "addr,a",
			Required: false,
			Usage:    "地址",
		},
	},
	Action: func(cctx *cli.Context) error {

		w, c, err := getwallet(cctx)
		defer c()
		if err != nil {
			return err
		}
		addr := w.Default(context.Background())
		if cctx.IsSet("addr") {
			addr, err = address.NewFromString(cctx.String("addr"))
			if err != nil {
				return err
			}
		}
		sign, err := hex.DecodeString(cctx.String("sign"))
		if err != nil {
			return err
		}
		var sig crypto.Signature
		if err := sig.UnmarshalBinary(sign); err != nil {
			return err
		}
		isv, err := w.Verify(context.Background(), addr.Payload(), []byte(cctx.String("msg")), &sig)
		if err != nil {
			return err
		}
		fmt.Printf("验证结果：%v\n", isv)

		return nil
	},
}

var ExportCmd = &cli.Command{
	Name:  "export",
	Usage: "导出",

	// Flags: []cli.Flag{
	// 	cli.IntFlag{
	// 		Name:  "type", // 配置名称
	// 		Value: 1,      // 缺省配置值
	// 		Usage: "SigType	SigTypeSecp256k1=1 SigTypeBLS=2", // 配置描述
	// 	},
	// },
	Action: func(cctx *cli.Context) error {

		w, c, err := getwallet(cctx)
		defer c()
		if err != nil {
			return err
		}

		hexs, err := w.Export(context.Background())
		if err != nil {
			return err
		}
		fmt.Println(hexs)

		return nil
	},
}

var ImportCmd = &cli.Command{
	Name:  "import",
	Usage: "创建一个新的地址",

	Flags: []cli.Flag{
		cli.StringFlag{
			Name:     "password2,p2",
			Value:    "123456",
			Usage:    "导入文本密码",
			Required: false,
		}, cli.StringFlag{
			Name:     "keyhexstr,khex",
			Value:    "",
			Usage:    "钱包密码",
			Required: true,
		},
	},
	Action: func(cctx *cli.Context) error {

		w, c, err := getwallet(cctx)
		defer c()
		if err != nil {
			return err
		}
		err = w.Import(context.Background(), cctx.String("keyhexstr"), cctx.String("password2"))
		if err != nil {
			return err
		}
		fmt.Println("导入成功")

		return nil
	},
}

var DefaultCmd = &cli.Command{
	Name:  "default",
	Usage: "显示默认地址",

	Flags: []cli.Flag{},
	Action: func(cctx *cli.Context) error {
		w, c, err := getwallet(cctx)
		defer c()
		if err != nil {
			return err
		}

		addr := w.Default(context.Background())

		fmt.Println(addr.String())

		return nil
	},
}

var SetdefaultCmd = &cli.Command{
	Name:  "setdefault",
	Usage: "设置默认地址",

	Flags: []cli.Flag{
		cli.StringFlag{
			Name:     "addr,a", // 配置名称
			Required: true,
			Usage:    "默认地址", // 配置描述
		},
	},
	Action: func(cctx *cli.Context) error {

		w, c, err := getwallet(cctx)
		defer c()
		if err != nil {
			return err
		}
		if !cctx.IsSet("addr") {
			return errors.New("addr is not set")
		}
		addr_f, err := address.NewFromString(cctx.String("addr"))
		if err != nil {
			return err
		}
		err = w.Setdefault(context.Background(), addr_f)
		if err != nil {
			return err
		}
		fmt.Println("设置成功")
		return nil
	},
}

var RpcCmd = &cli.Command{
	Name:  "rpc",
	Usage: "开启本地rpc服务",

	Flags: []cli.Flag{},
	Action: func(cctx *cli.Context) error {

		d, err := leveldb.OpenFile(filepath.Dir(os.Args[0]), nil)
		if err != nil {
			return err
		}
		defer d.Close()
		if err != nil {
			return err
		}
		w, err := Newwallet(cctx.GlobalString("password"), d)
		if err != nil {
			return err
		}
		fmt.Printf("wallet local rpcserver start at %s\n", cctx.GlobalString("url"))
		err = w.StratrpcServer(cctx.GlobalString("url"))
		if err != nil {
			return err
		}
		return nil
	},
}
